package com.bsd.xxyp.rdlock.executor;

import com.bsd.xxyp.rdlock.entity.LockInfo;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;

/**
 * @author ：wangcheng
 * @date 2022/12/6
 **/
@Slf4j
public class JedisLockExecutor implements LockExecutor {

    private JedisCluster jedis;

    public JedisLockExecutor(JedisCluster jedis) {
        this.jedis = jedis;
    }

    private static final String SET_IF_NOT_EXIST = "NX";

    private static final String SET_WITH_EXPIRE_MILL_TIME = "PX";

    private static final String LOCK_SUCCESS = "OK";

    private static final String SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

    private static final Long RELEASE_SUCCESS = 1L;


    @Override
    public boolean tryAcquire(LockInfo lockInfo) {
        String lockValue = getRequestId();
        lockInfo.setLockValue(lockValue);
        boolean lock = tryGetDistributeLock(lockInfo.getLockKey(), lockValue, lockInfo.getLockTimeout());
        if (!lock) {
            try {
                Thread.sleep(lockInfo.getWaitTime());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return lock;
    }

    @Override
    public boolean releaseLock(LockInfo lockInfo) {
        if (lockInfo.isLockSuccess()) {
            return releaseDistributedLock(lockInfo.getLockKey(),lockInfo.getLockValue());
        }else {
            log.info("rdLock: currentThread not hold lock so no need releaseLock ,lockKey: {} ",lockInfo.getLockKey());
            return false;
        }
    }

    public  boolean tryGetDistributeLock(String lockKey, String requestId, long expireTime) {
        //如果版本问题导致没有该api，可变更版本 SetParams高版本才有
        //String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_MILL_TIME, expireTime);
        String result = jedis.set(lockKey, requestId,SetParams.setParams().nx().px(expireTime));
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }

    public  boolean releaseDistributedLock(String lockKey, String requestId) {
        Object result = jedis.eval(SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        return RELEASE_SUCCESS.equals(result);
    }


}
